/**
 *  Serponix is an arcade game in focus to multiplayer based on the classic game Snake.
 *  Copyright (C) 2010 - 2011  Daniel Vala
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License,
 *  or  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  If you have any question do not hesitate to contact author
 *  on e-mail address: danielvala42@gmail.com
 */
package com.serponix.gui.lobby;

import com.serponix.game.GameModeEnum;
import com.serponix.game.Mapa;
import com.serponix.game.Player;
import com.serponix.gui.MainPanel;
import com.serponix.net.Informace;
import com.serponix.net.Server;
import com.serponix.net.UDPServer;
import com.serponix.settings.GameSettings;
import java.net.DatagramPacket;
import java.util.ArrayList;
import java.util.List;

/**
 * Model lobby pro server rozšiřuje model
 * o parametry a metody specifické pro server.
 *
 * @author Daniel Vala
 */
public class ModelLobbyServer extends ModelLobby {

	private Server server;
	// Hráči, které je možno vybrat do hry
	private List<Player> hraci;
	// Aktuálne vybraní hráči do hry, starají se o ně modelyComboBoxů
	private List<Player> vybraniHraci;
	private List<ModelComboBoxHrace> modelyComboBoxuHracu;
	private Mapa mapa;

	public ModelLobbyServer(MainPanel okno) {
		super(okno);
		server = new UDPServer(this);
		setNet(server);
		mapa = new Mapa();
		hraci = new ArrayList<Player>();
		vybraniHraci = new ArrayList<Player>();
		modelyComboBoxuHracu = new ArrayList<ModelComboBoxHrace>();

		GameSettings gameSettings = GameSettings.getInstance();
		Player.Control[] ovladani = { Player.Control.KEYBOARD1, Player.Control.KEYBOARD2, Player.Control.KEYBOARD3, Player.Control.KEYBOARD4 };
		for (int i = 0; i < gameSettings.getNumberOfActivePlayers(); i++) {
			hraci.add(new Player(getJmenoHrace(i), ovladani[i], null));
		}

		setGameMode(gameSettings.getGameMode());
		setRychlostHry(gameSettings.getSpeed());
		setNazevMapy("prázdná mapa");

		new Thread(server).start();
	}

	public void vyhodHrace(int cisloComboBoxu) {
		Player hrac = getModelyComboBoxuHracu().get(cisloComboBoxu).getPredchoziHrac();
		server.posliDataKlientovi(Informace.VYHODIT + Informace.ODDELOVAC1, hrac.getPacket());
		hraci.remove(hrac);
		getModelyComboBoxuHracu().get(cisloComboBoxu).setSelectedItem("OTEVŘENO");
	}

	public void odstranHrace(Player hrac) {
		hraci.remove(hrac);
		for (int i = 0; i < getModelyComboBoxuHracu().size(); i++) {
			if (getModelyComboBoxuHracu().get(i).getSelectedItem().equals(hrac)) {
				getModelyComboBoxuHracu().get(i).setSelectedItem("OTEVŘENO");
				getModelyComboBoxuHracu().get(i).vyberChaged();
			}
		}
	}

	public Server getServer() {
		return server;
	}

	public Mapa getMapa() {
		return mapa;
	}

	public void setMapa(Mapa mapa) {
		setNazevMapy(mapa.getNazev());
		this.mapa = mapa;
		getServer().poslatData(Informace.NAZEV_MAPY + Informace.ODDELOVAC1 + getMapa().getNazev());
	}

	public List<ModelComboBoxHrace> getModelyComboBoxuHracu() {
		return modelyComboBoxuHracu;
	}

	/**
	 * Vrátí seznam všech hráčů.
	 *
	 * @return Seznam všech hráčů.
	 */
	public List<Player> getHraci() {
		return hraci;
	}

	/**
	 * Vrátí seznam hráčů, kteří jsou již vybrání v některém z comboBoxů.
	 *
	 * @return Seznam hráčů.
	 */
	public List<Player> getVybraniHraci() {
		return vybraniHraci;
	}

	public boolean isAIPlaying() {
		for (int i = 0; i < vybraniHraci.size(); i++) {
			if (vybraniHraci.get(i).getOvladani() == Player.Control.AI_STANDARD) {
				return true;
			}
		}
		return false;
	}

	public boolean isClientPlaying() {
		for (int i = 0; i < vybraniHraci.size(); i++) {
			if (vybraniHraci.get(i).getOvladani() == Player.Control.CLIENT) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Přidá nového hráče a zobrazí ho na volné pozici, pokud existuje.
	 *
	 * @param hrac Nový hráč.
	 */
	public boolean addHrac(Player hrac) {
		boolean uspech = zobrazHraceNaVolnePozici(hrac);
		if (uspech) {
			hraci.add(hrac);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Zobrazí daného hráče na první pozici OTEVŘENO, pokud existuje.
	 *
	 * @param hrac Hráč k zobrazení.
	 * @return true, pokud pro hráče byla volná pozice. Jinak false.
	 */
	private boolean zobrazHraceNaVolnePozici(Player hrac) {
		for (int i = 0; i < modelyComboBoxuHracu.size(); i++) {
			if (modelyComboBoxuHracu.get(i).getSelectedItem().equals("OTEVŘENO")) {
				modelyComboBoxuHracu.get(i).setSelectedItem(hrac);
				modelyComboBoxuHracu.get(i).vyberChaged();
				return true;
			}
		}
		return false;
	}

	/**
	 * Pošle klientům stavy výběru všech comboBoxů hráčů.
	 */
	public void posliStavyComboBoxu() {
		for (int i = 0; i < modelyComboBoxuHracu.size(); i++) {
			modelyComboBoxuHracu.get(i).posliStav();
		}
	}

	public void sendGameMode() {
		server.poslatData(Informace.GAME_MODE + Informace.ODDELOVAC1 + getGameMode().getKey());
	}

	public void posliStavRychlosti() {
		server.poslatData(Informace.RYCHLOST + Informace.ODDELOVAC1 + getRychlostHry());
	}

	public void posliVsechnyInformace() {
		posliStavRychlosti();
		sendGameMode();
		posliStavyComboBoxu();
	}

	public void posliVsechnyInformace(DatagramPacket packet) {
		server.posliDataKlientovi(Informace.RYCHLOST + Informace.ODDELOVAC1 + getRychlostHry(), packet);
		server.posliDataKlientovi(Informace.GAME_MODE + Informace.ODDELOVAC1 + getGameMode().getKey(), packet);
		server.posliDataKlientovi(Informace.NAZEV_MAPY + Informace.ODDELOVAC1 + getMapa().getNazev(), packet);
		for (int i = 0; i < modelyComboBoxuHracu.size(); i++) {
			modelyComboBoxuHracu.get(i).posliStavKlientovi(packet);
		}
	}

	/**
	 * Vytvoří nový modelComboBoxHrace, přidá ho do seznamu a vrátí ho.
	 *
	 * @param cislo Číslo daného comboBoxu, tj. kolik už jich je vytvořeno + 1.
	 * @return Nově vytvořený comboBoxModel.
	 */
	public ModelComboBoxHrace createAndReturnModelComboBoxHrace(int cislo) {
		ModelComboBoxHrace retval = new ModelComboBoxHrace(this, cislo, server);
		modelyComboBoxuHracu.add(retval);
		return retval;
	}

	/**
	 * Nastaví danou rychlost hry a pošle nastavení všem klientům.
	 *
	 * @param rychlostHry Nová rychlost hry.
	 */
	public void setRychlostHryAPosliKlientum(int rychlostHry) {
		setRychlostHry(rychlostHry);
		server.poslatData(Informace.RYCHLOST + Informace.ODDELOVAC1 + rychlostHry);
	}

	/**
	 * Sets new game mode and send it to all clients..
	 *
	 * @param gameMode New game mode to be set and send.
	 */
	@Override
	public void setGameMode(GameModeEnum mode) {
		super.setGameMode(mode);
		sendGameMode();
	}
}
